home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / borland / fastclok.zip / fastclok.c next >
C/C++ Source or Header  |  1994-04-07  |  4KB  |  157 lines

  1. /*
  2.  *    This file contains the implementation of a more precise time
  3.  * than that provided by DOS.  Routines are provided to increase the
  4.  * clock rate to around 1165 interrupts per second, for a granularity
  5.  * of close to 858 microseconds between clock pulses, rather than the
  6.  * 55 milliseconds between normal PC clock pulses (18.2 times/second).
  7.  *    The gettimeofday() routine acts like the Unix version, with
  8.  * the exception that time zone does not matter.  The time will be returned
  9.  * in timeval structures that match thier Unix counterparts.
  10.  *    Note that the start_fasttimer() routine must be called before
  11.  * the gettimeofday() routines will work, and that the stop_fasttimer()
  12.  * routine MUST be called before the program terminates, or the machine
  13.  * will be toasted.  For this reason, start_fasttimer() installs the
  14.  * stop_fasttimer() routine to be called at program exit.
  15.  */
  16.  
  17. #include    <stdlib.h>
  18. #include    <dos.h>
  19. #include    <time.h>
  20. #include    <sys/nfs_time.h>
  21. #include    "fastclok.h"
  22.  
  23. #define    CLOCK_INT    (0x08)
  24. #define    USEC_INC    (858)
  25.  
  26. #pragma    option    -N-            // Do not check for stack overflow
  27.  
  28.  
  29. static    int    fastclock_on = 0;    // Is the clock speed set higher?
  30. static    struct    timeval    nowtime;    // Current time
  31. static    void    interrupt (*oldfunc)(void);    // interrupt function pointer
  32.  
  33.  
  34.  
  35. /*    This routine will handle the clock interrupt at its higher rate.
  36.  * It will call the DOS handler every 64 times it is called, to maintain
  37.  * the 18.2 times per second that DOS needs to be called.  Each time through,
  38.  * it adds to the nowtime value.
  39.  *    When it is not calling the DOS handler, this routine must reset
  40.  * the 8259A interrupt controller before returning. */
  41.  
  42. static    void    interrupt handle_clock(void) {
  43.     static    int    callmod = 0;
  44.  
  45.     /* Increment the time */
  46.     nowtime.tv_usec += USEC_INC;
  47.     if (nowtime.tv_usec > 1000000L) {
  48.         nowtime.tv_sec++;
  49.         nowtime.tv_usec -= 1000000L;
  50.     }
  51.  
  52.     /* Increment the callmod */
  53.     callmod = (callmod+1)%64;
  54.  
  55.     /* If this is the 64th call, then call handler */
  56.     if (callmod == 0) {
  57.         oldfunc();
  58.  
  59.     /* Otherwise, clear the interrupt controller */
  60.     } else {
  61.         outp(0x20,0x20);    // End of interrupt
  62.     }
  63. }
  64.  
  65.  
  66. /*    This routine will stop the fast clock if it is going.  It
  67.  * has void return value so that it can be an exit procedure. */
  68.  
  69. void    stop_fastclock(void) {
  70.  
  71.     /* See if the clock is on - exit if not */
  72.     if (!fastclock_on) {
  73.         return;
  74.     }
  75.  
  76.     /* Disable interrupts */
  77.     asm {cli};
  78.  
  79.     /* Reinstate the old interrupt handler */
  80.     setvect(CLOCK_INT, oldfunc);
  81.  
  82.     /* Reinstate the clock rate to 18.2 Hz */
  83.     outp(0x43, 0x36);    // Set up for count to be sent
  84.     outp(0x40, 0x00);    // LSB = 00  \_together make 65536 (0)
  85.     outp(0x40, 0x00);    // MSB = 00  /
  86.  
  87.     /* Enable interrupts */
  88.     asm {sti};
  89.  
  90.     /* Mark clock is not fast */
  91.     fastclock_on = 0;
  92. }
  93.  
  94.  
  95. /*    This routine will start the fast clock rate by installing the
  96.  * handle_clock routine as the interrupt service routine for the clock
  97.  * interrupt and then setting the interrupt rate up to its higher speed
  98.  * by programming the 8253 timer chip.
  99.  *    This routine does nothing if the clock rate is already set to
  100.  * its higher rate, but then it returns -1 to indicate the error.
  101.  */
  102.  
  103. int    start_fastclock(void) {
  104.  
  105.     /* Make sure the clock is not already set faster */
  106.     if (fastclock_on) {
  107.         return(-1);
  108.     }
  109.  
  110.     /* Disable interrupts */
  111.     asm {cli};
  112.  
  113.     /* Store the old interrupt handler */
  114.     oldfunc = getvect(CLOCK_INT);
  115.  
  116.     /* Install the new interrupt handler */
  117.     setvect(CLOCK_INT,handle_clock);
  118.  
  119.     /* Increase the clock rate */
  120.     outp(0x43, 0x36);    // Set up for count to be sent
  121.     outp(0x40, 0x00);    // LSB = 00  \_together make 2^10 = 1024
  122.     outp(0x40, 0x04);    // MSB = 04  /
  123.  
  124.     /* Set the time to seconds since GMT whatever time/date */
  125.     nowtime.tv_sec = time(NULL);
  126.     nowtime.tv_usec = 0;
  127.  
  128.     /* Install the stop_fastclock() routine to be called at exit */
  129.     atexit(stop_fastclock);
  130.  
  131.     /* Enable interrupts */
  132.     asm {sti};
  133.  
  134.     /* Mark the clock as faster */
  135.     fastclock_on = 1;
  136.     return(0);
  137. }
  138.  
  139.  
  140. /*    This routine will return the present value of the time, which is
  141.  * read from the nowtime structure.  Interrupts are disabled during this
  142.  * time to prevent the clock from changing while it is being read.
  143.  */
  144.  
  145. void    getfasttime(struct timeval *time) {
  146.  
  147.     /* Disable interrupts */
  148.     asm {cli};
  149.  
  150.     /* Read the time */
  151.     *time = nowtime;
  152.  
  153.     /* Enable interrupts */
  154.     asm {sti};
  155. }
  156.  
  157.